#!/usr/bin/env python3

import socket
import os
import sys
import select
import datetime
import vt

line = []
start = 0

def msg(s):
    vt.run([vt.goto(1, 1), vt.clearLine(), vt.color(s, vt.RED)])
    #  print('\033[1;1H\033[2K%s' % s, end='', flush=True)

def show(name, data):
    global line, start

    out = "%s(%s): %s" % (name, datetime.datetime.now().strftime("%T"), data)
    line.append(out)
    num = len(line)
    if num > 10:
        start += 1

    vt.save(False)
    for i in range(10):
        if i < num:
            vt.run([vt.goto((i + 1), 1), vt.clearLine(),
                vt.color(line[start + i], vt.RED)])
            #  print("\033[%d;1H\033[2K%s" % (i + 1, line[start + i]),
                    #  end='', flush=True)
        else:
            vt.run([vt.goto(i, 1), vt.LINE])
            #  print("\033[%d;1H\033[2K" % i)
    vt.load(False)
    #  print("\033[u", end='', flush=True)

def outRecvData(sd, name="服务端"):
    data, addr = sd.recvfrom(1024)
    data = data.decode()
    if data == 'exit':
        return None

    show(addr[0], data)

    return addr

def sendInputData(sd, addr, name="服务端"):
    data = input(vt.goto(13, 1) + vt.run(vt.LINE) + vt.color(name + "发送:", vt.BLUE))
    #  data = input("\033[13;1H\033[2K%s发送: " % name)
    if data:
        sd.sendto(data.encode(), addr)
        if data == 'exit':
            return None

        show('本地发送', data)

    return True

def chatHandle(sd, addr, name="服务端"):

    sdNo = sd.fileno()
    inNo = 0

    while True:
        r, *o = select.select([inNo, sdNo], [], [])

        if inNo in r and not sendInputData(sd, addr, name):
            break

        if sdNo in r and not outRecvData(sd, name):
            break

    sd.close()
    vt.run([vt.goto(15,1), vt.LINE])
    #  print("\033[15;1H\033[2K", end='', flush=True)

def findSrv(port):
    sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #   开启广播功能
    sd.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    #   发送查找服务器的广播包
    sd.sendto('请求链接'.encode('utf-8'), ('255.255.255.255', port))

    msg("正在查找服务器......")
    r, *w = select.select([sd.fileno()], [], [], 3)

    if r:
        data, addr = sd.recvfrom(1024)
        msg("找到服务器(%s), 准备开始通信..." % addr[0])
        return sd, addr, '客户端'
    sd.close()

    return None

def createSrv(addr):
    sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sd.bind(addr)
    msg("正在等待客户端发送数据.....")
    data, addr = sd.recvfrom(1024)
    msg("接收到 %s 客户端的请求链接....." % addr[0])
    sd.close()
    sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sd.sendto('请求通过'.encode('utf-8'), addr)
    name = '服务端'

    return sd, addr, name

def main():
    #   没有参数: 9000
    #   一个参数: 绑定端口号
    port = int(sys.argv[1]) if len(sys.argv) == 2 else 9000
    addr = ("0.0.0.0", port)

    vt.clear(back=False)
    #  print('\033[2J', end='', flush=True)

    srv = findSrv(port)
    if srv: #有服务器
        sd, addr, name = srv
    else: #无服务器
        msg("没有查找到服务器,准备创建服务器......")
        sd, addr, name = createSrv(addr)

    chatHandle(sd, addr, name)

if __name__ == "__main__":
    main()
